import time
import re
from typing import Optional, Sequence, Tuple, List

try:
    from pywinauto import Desktop
    from pywinauto.keyboard import send_keys
except Exception:  # pragma: no cover
    Desktop = None
    send_keys = None

# 新增：直接使用 pyautogui 以支持基于鼠标位置的输入
try:
    import pyautogui
    pyautogui.FAILSAFE = False
except Exception:  # pragma: no cover
    pyautogui = None

from .vision import VisionEngine, BBox
from .config import CV_OCR_FALLBACK


class ComputerController:
    """
    OpenInterpreter-like controller implementing an observe–act–verify loop
    over generic GUI operations, with vision-first actions and UIA fallbacks.
    """

    def __init__(self) -> None:
        self.vision = VisionEngine()

    # ---------- window helpers ----------
    def _find_window(self, title_contains: Optional[str] = None, backend: str = "uia"):
        if Desktop is None:
            return None
        try:
            if title_contains:
                patt = f".*{re.escape(title_contains)}.*"
                win = Desktop(backend=backend).window(title_re=patt)
            else:
                # Fallback to any active top-level window
                win = Desktop(backend=backend).active()
            if hasattr(win, "exists"):
                win.wait("exists ready", timeout=5)
            return win
        except Exception:
            return None

    def get_window_rect(self, title_contains: Optional[str] = None, backend: str = "uia") -> Optional[Tuple[int, int, int, int]]:
        """Return (x, y, w, h) of window rect if found."""
        win = self._find_window(title_contains=title_contains, backend=backend)
        if not win:
            return None
        try:
            r = win.rectangle()
            # rectangle has left, top, right, bottom
            x, y = int(r.left), int(r.top)
            w, h = int(r.right - r.left), int(r.bottom - r.top)
            return (x, y, w, h)
        except Exception:
            return None

    def focus_window(self, title_contains: Optional[str] = None, backend: str = "uia") -> bool:
        win = self._find_window(title_contains=title_contains, backend=backend)
        if not win:
            return False
        try:
            win.set_focus()
            return True
        except Exception:
            try:
                win.wrapper_object().set_focus()
                return True
            except Exception:
                return False

    # ---------- observe ----------
    def find_text_bbox_in_window(self, text: str, title_contains: str) -> Optional[BBox]:
        """Crop to window ROI and locate text using Aliyun or local OCR."""
        try:
            img = self.vision.capture_screen()
            if img is None:
                return None
            rect = self.get_window_rect(title_contains)
            if rect is None:
                return None
            rx, ry, rw, rh = rect
            try:
                crop = img.crop((rx, ry, rx + rw, ry + rh))
            except Exception:
                return None
            # Prefer Aliyun
            bb = None
            try:
                if self.vision.engine == "aliyun":
                    bb = self.vision._aliyun_locate_text(crop, text)
                elif CV_OCR_FALLBACK:
                    bb = self.vision._ocr_locate_text(crop, text)
            except Exception:
                bb = None
            if bb:
                return BBox(bb.x + rx, bb.y + ry, bb.w, bb.h)
            return None
        except Exception:
            return None

    def observe_text(self, text: str, title_contains: Optional[str] = None) -> bool:
        """Check if text is visible, optionally within a window ROI."""
        region = None
        if title_contains:
            region = self.get_window_rect(title_contains)
        try:
            if region:
                bb = self.find_text_bbox_in_window(text, title_contains)
            else:
                bb = self.vision.find_text_bbox(text)
            return bool(bb)
        except Exception:
            return False

    # ---------- utils ----------
    @staticmethod
    def _norm(s: str) -> str:
        s = (s or "").lower().strip()
        s = re.sub(r"\s+", "", s)
        s = re.sub(r"[，。！？；、,.!?;:（）()【】《》\"'·\-—_]", "", s)
        return s

    @staticmethod
    def _fuzzy_match(a: str, b: str, threshold: float = 0.6) -> bool:
        try:
            import difflib
            ra = ComputerController._norm(a)
            rb = ComputerController._norm(b)
            if not ra or not rb:
                return False
            if ra in rb or rb in ra:
                return True
            return difflib.SequenceMatcher(None, ra, rb).ratio() >= threshold
        except Exception:
            return a == b

    # ---------- act ----------
    def click_text_or_uia(self, text: str, title_contains: Optional[str] = None, control_types: Sequence[str] = ("Button", "ListItem", "TreeItem", "DataItem", "Text", "Edit")) -> bool:
        """Vision-first click; if it fails, try UIA element click within target window."""
        # Vision-first (global or ROI if window known)
        region = None
        if title_contains:
            region = self.get_window_rect(title_contains)
        if region:
            bb = self.find_text_bbox_in_window(text, title_contains)
            if bb and self.vision.click_bbox(bb):
                return True
        else:
            if self.vision.click_text(text):
                return True

        # UIA fallback
        if Desktop is None:
            return False
        try:
            win = self._find_window(title_contains=title_contains, backend="uia")
            if not win:
                return False
            # Prefer direct match by title
            try:
                ctrl = win.child_window(title_re=f".*{re.escape(text)}.*")
                if ctrl.exists():
                    ctrl = ctrl.wrapper_object()
                    try:
                        ctrl.click_input()
                        return True
                    except Exception:
                        pass
            except Exception:
                pass
            # Enumerate by common control types
            items = []
            for ct in control_types:
                try:
                    items.extend(win.descendants(control_type=ct))
                except Exception:
                    continue
            # Pick the best fuzzy match
            best = None
            best_name = ""
            best_score = 0.0
            try:
                import difflib
            except Exception:
                difflib = None
            for it in items:
                name = ""
                try:
                    name = (it.window_text() or "").strip()
                except Exception:
                    try:
                        name = (getattr(it, "element_info", None).name or "").strip()
                    except Exception:
                        name = ""
                if not name:
                    continue
                # compute fuzzy score
                score = 0.0
                if difflib is not None:
                    try:
                        score = difflib.SequenceMatcher(None, self._norm(text), self._norm(name)).ratio()
                    except Exception:
                        score = 0.0
                else:
                    score = 1.0 if text in name else 0.0
                if score >= 0.6 and score > best_score:
                    best = it
                    best_name = name
                    best_score = score
            if best is not None:
                try:
                    best.click_input()
                    return True
                except Exception:
                    pass
        except Exception:
            return False
        return False

    def search_and_select(self, title_contains: str, terms: List[str], verify_text: Optional[str] = None) -> bool:
        """Use UIA to find the search Edit in window, input terms, press Enter and try selection; verify by text."""
        if Desktop is None or send_keys is None:
            return False
        try:
            win = self._find_window(title_contains=title_contains, backend="uia")
            if not win:
                return False
            # Find search Edit
            edit = None
            for patt in ["搜索", "Search", "查找"]:
                try:
                    edit = win.child_window(title_re=f".*{patt}.*", control_type="Edit").wrapper_object()
                    break
                except Exception:
                    edit = None
            if edit is None:
                try:
                    edit = win.child_window(control_type="Edit").wrapper_object()
                except Exception:
                    edit = None
            if edit is None:
                return False
            edit.click_input()
            time.sleep(0.4)
            for term in terms:
                try:
                    from pywinauto import clipboard
                    clipboard.SetText(term)
                    send_keys("^a")
                    time.sleep(0.1)
                    send_keys("^v")
                except Exception:
                    send_keys("^a")
                    time.sleep(0.1)
                    send_keys(term)
                time.sleep(0.8)
                send_keys("{ENTER}")
                time.sleep(1.0)
                # Try Down + Enter to confirm first result
                send_keys("{DOWN}")
                time.sleep(0.3)
                send_keys("{ENTER}")
                time.sleep(0.8)
                if verify_text and self.observe_text(verify_text, title_contains=title_contains):
                    return True
            return False
        except Exception:
            return False

    def ensure_message_edit_focus(self, title_contains: str) -> bool:
        """Try to focus the main message Edit within the window (excluding search Edit)."""
        if Desktop is None:
            from .logger import log_event
            log_event("EDIT_FOCUS_FAIL", "Desktop=None")
            return False
        try:
            from .logger import log_event
            log_event("EDIT_FOCUS_START", f"title={title_contains}")
            
            win = self._find_window(title_contains=title_contains, backend="uia")
            if not win:
                log_event("EDIT_FOCUS_UIA_FAIL", "trying_win32_fallback")
                # 回退到 Win32 后端（兼容 Win10 记事本）
                win = self._find_window(title_contains=title_contains, backend="win32")
                if not win:
                    log_event("EDIT_FOCUS_FAIL", "window_not_found_both_backends")
                    return False
                else:
                    log_event("EDIT_FOCUS_WIN32_OK", "using_win32_backend")
            
            # Find all edits and pick one with largest rectangle that isn't named '搜索'
            edits = []
            try:
                edits = win.descendants(control_type="Edit")
                log_event("EDIT_FOCUS_SEARCH", f"found_edits={len(edits)}")
            except Exception as e:
                log_event("EDIT_FOCUS_SEARCH", f"descendants_fail={e}")
                edits = []
            
            best = None
            best_area = 0
            for i, ed in enumerate(edits):
                name = ""
                try:
                    name = (ed.window_text() or "").strip()
                except Exception:
                    name = ""
                try:
                    r = ed.rectangle()
                    area = max(1, (r.right - r.left) * (r.bottom - r.top))
                except Exception:
                    area = 0
                
                log_event("EDIT_FOCUS_CANDIDATE", f"edit_{i}: name='{name}', area={area}")
                
                if "搜索" in name or "Search" in name:
                    log_event("EDIT_FOCUS_SKIP", f"edit_{i}: search_control")
                    continue
                if area > best_area:
                    best = ed
                    best_area = area
                    log_event("EDIT_FOCUS_BEST", f"edit_{i}: new_best_area={area}")
            
            if best is not None:
                try:
                    log_event("EDIT_FOCUS_CLICK", f"best_area={best_area}")
                    best.click_input()
                    log_event("EDIT_FOCUS_SUCCESS", "click_input_ok")
                    return True
                except Exception as e:
                    log_event("EDIT_FOCUS_CLICK_FAIL", f"error={e}")
                    return False
            
            # 如果没有找到 Edit，尝试在窗口底部文本区点击一下以激活输入
            log_event("EDIT_FOCUS_FALLBACK", "no_edit_found, try_bottom_click")
            rect = self.get_window_rect(title_contains)
            if rect:
                rx, ry, rw, rh = rect
                # 在底部上方 60px 左右区域点击一次
                cx = rx + rw // 2
                cy = ry + rh - 60
                log_event("EDIT_FOCUS_FALLBACK", f"bottom_click=({cx},{cy})")
                try:
                    self.vision.click_bbox(BBox(cx - 2, cy - 2, 4, 4))
                    log_event("EDIT_FOCUS_SUCCESS", "bottom_click_ok")
                    return True
                except Exception as e:
                    log_event("EDIT_FOCUS_FAIL", f"bottom_click_fail={e}")
                    return False
            
            log_event("EDIT_FOCUS_FAIL", "no_rect")
            return False
        except Exception as e:
            from .logger import log_event
            log_event("EDIT_FOCUS_EXCEPTION", f"error={e}")
            return False

    # 复合输入：中心点击 + 聚焦最大编辑控件 + 选择全部并粘贴
    def type_text_in_window_center_focus(self, title_contains: Optional[str], text: str, press_enter: bool = False) -> bool:
        try:
            from .logger import log_event
            log_event("CENTER_FOCUS_START", f"title={title_contains}, text_len={len(text)}")
            
            # 先尝试置焦窗口
            focus_ok = self.focus_window(title_contains)
            log_event("CENTER_FOCUS_WINDOW", f"focus_ok={focus_ok}")
            
            rect = self.get_window_rect(title_contains)
            if rect is None:
                log_event("CENTER_FOCUS_FAIL", "window_rect=None")
                return False
            
            rx, ry, rw, rh = rect
            cx = rx + rw // 2
            cy = ry + int(rh * 0.4)
            log_event("CENTER_FOCUS_CLICK", f"pos=({cx},{cy}), rect=({rx},{ry},{rw},{rh})")
            
            try:
                self.vision.click_bbox(BBox(cx - 2, cy - 2, 4, 4))
                log_event("CENTER_FOCUS_CLICK", "method=vision.click_bbox")
            except Exception as e:
                log_event("CENTER_FOCUS_CLICK", f"vision_fail={e}, fallback=pyautogui")
                if pyautogui is None:
                    log_event("CENTER_FOCUS_FAIL", "pyautogui=None")
                    return False
                pyautogui.click(cx, cy)
            
            time.sleep(0.15)
            
            # 聚焦最大编辑控件
            edit_focus_ok = self.ensure_message_edit_focus(title_contains)
            log_event("CENTER_FOCUS_EDIT", f"edit_focus_ok={edit_focus_ok}")
            
            time.sleep(0.15)
            
            # 选择全部并粘贴（提高可见性）
            try:
                if send_keys is not None:
                    try:
                        import win32clipboard
                        import win32con
                        # 使用 Windows API 设置剪贴板
                        win32clipboard.OpenClipboard()
                        win32clipboard.EmptyClipboard()
                        win32clipboard.SetClipboardText(text, win32con.CF_UNICODETEXT)
                        win32clipboard.CloseClipboard()
                        log_event("CENTER_FOCUS_PASTE", "method=win32clipboard+send_keys")
                    except Exception:
                        try:
                            from pywinauto import clipboard
                            clipboard.SetText(text)
                            log_event("CENTER_FOCUS_PASTE", "method=pywinauto_clipboard+send_keys")
                        except Exception:
                            # 如果剪贴板都失败，直接用 typewrite
                            raise Exception("clipboard_failed")
                    send_keys("^a")
                    time.sleep(0.05)
                    send_keys("^v")
                else:
                    log_event("CENTER_FOCUS_PASTE", "method=pyautogui.typewrite")
                    if pyautogui is None:
                        log_event("CENTER_FOCUS_FAIL", "pyautogui=None")
                        return False
                    pyautogui.typewrite(text, interval=0.02)
            except Exception as e:
                log_event("CENTER_FOCUS_PASTE", f"primary_fail={e}, fallback=typewrite")
                try:
                    if pyautogui is None:
                        log_event("CENTER_FOCUS_FAIL", "pyautogui=None")
                        return False
                    pyautogui.typewrite(text, interval=0.02)
                except Exception as e2:
                    log_event("CENTER_FOCUS_FAIL", f"typewrite_fail={e2}")
                    return False
            
            # 退出中文候选
            try:
                if send_keys is not None:
                    send_keys("{ESC}")
                    log_event("CENTER_FOCUS_ESC", "sent")
            except Exception as e:
                log_event("CENTER_FOCUS_ESC", f"fail={e}")
                pass
            
            if press_enter:
                try:
                    if send_keys is not None:
                        send_keys("{ENTER}")
                        log_event("CENTER_FOCUS_ENTER", "send_keys")
                    else:
                        if pyautogui is not None:
                            pyautogui.press("enter")
                            log_event("CENTER_FOCUS_ENTER", "pyautogui")
                except Exception as e:
                    log_event("CENTER_FOCUS_ENTER", f"fail={e}")
                    pass
            
            log_event("CENTER_FOCUS_SUCCESS", "completed")
            return True
        except Exception as e:
            from .logger import log_event
            log_event("CENTER_FOCUS_EXCEPTION", f"error={e}")
            return False

    def type_text(self, text: str, press_enter: bool = False) -> bool:
        try:
            if send_keys is not None:
                try:
                    from pywinauto import clipboard
                    clipboard.SetText(text)
                    send_keys("^v")
                except Exception:
                    return self.vision.type_text(text, press_enter=press_enter)
                time.sleep(0.1)
                if press_enter:
                    try:
                        send_keys("{ENTER}")
                    except Exception:
                        pass
                return True
            return self.vision.type_text(text, press_enter=press_enter)
        except Exception:
            return self.vision.type_text(text, press_enter=press_enter)

    # 新增：以鼠标当前位置为基准的输入（先在鼠标处点击获取焦点，再粘贴/键入）
    def type_text_at_mouse(self, text: str, press_enter: bool = False) -> bool:
        try:
            if pyautogui is None:
                # 退回到常规输入
                return self.type_text(text, press_enter=press_enter)
            # 在当前位置单击以确保焦点到达鼠标处
            try:
                x, y = pyautogui.position()
                pyautogui.click(x, y, duration=0.05)
            except Exception:
                # 若点击失败，直接尝试输入
                pass
            time.sleep(0.1)
            # 优先剪贴板粘贴，失败则键入
            try:
                if send_keys is not None:
                    from pywinauto import clipboard
                    clipboard.SetText(text)
                    send_keys("^v")
                else:
                    pyautogui.typewrite(text, interval=0.02)
            except Exception:
                try:
                    pyautogui.typewrite(text, interval=0.02)
                except Exception:
                    return False
            # 退出中文输入法候选，确保已落入编辑框
            try:
                if send_keys is not None:
                    send_keys("{ESC}")
            except Exception:
                pass
            # 可选：按回车
            if press_enter:
                try:
                    if send_keys is not None:
                        send_keys("{ENTER}")
                    else:
                        pyautogui.press("enter")
                except Exception:
                    pass
            return True
        except Exception:
            return False

    def send_message_in_window(self, title_contains: str, text: str) -> bool:
        """Focus input, type text, and try multiple send methods with verification."""
        try:
            # 1) 确保窗口和输入框聚焦
            self.focus_window(title_contains)
            time.sleep(0.2)
            self.ensure_message_edit_focus(title_contains)
            time.sleep(0.2)
            # 2) 输入文本
            ok_type = self.type_text(text, press_enter=False)
            time.sleep(0.3)
            if send_keys is not None:
                try:
                    send_keys("{ESC}")  # 退出中文输入法候选
                except Exception:
                    pass
            time.sleep(0.3)
            # 3) 发送：Enter -> Ctrl+Enter -> Alt+S -> 点击“发送”
            sent = False
            if send_keys is not None:
                try:
                    send_keys("{ENTER}")
                    time.sleep(0.8)
                    if self.observe_text(text, title_contains=title_contains):
                        return True
                    # 验证简化：仅基于视觉确认，不进行剪贴板复制，避免阻塞
                    try:
                        if self.observe_text(text, title_contains=title_contains):
                            return True
                    except Exception:
                        pass
                except Exception:
                    pass
                try:
                    send_keys("^\n")  # Ctrl+Enter
                    time.sleep(0.8)
                    if self.observe_text(text, title_contains=title_contains):
                        return True
                    # 验证简化：仅基于视觉确认，不进行剪贴板复制，避免阻塞
                    try:
                        if self.observe_text(text, title_contains=title_contains):
                            return True
                    except Exception:
                        pass
                except Exception:
                    pass
                try:
                    send_keys("%s")  # Alt+S
                    time.sleep(0.8)
                    if self.observe_text(text, title_contains=title_contains):
                        return True
                    # 验证简化：仅基于视觉确认，避免剪贴板复制阻塞
                    try:
                        if self.observe_text(text, title_contains=title_contains):
                            return True
                    except Exception:
                        pass
                except Exception:
                    pass
            # UIA/视觉点击“发送”
            try:
                sent = False
                for label in ("发送", "Send", "发送(S)", "发送(&S)"):
                    if self.click_text_or_uia(label, title_contains=title_contains):
                        sent = True
                        break
                if sent:
                    time.sleep(0.8)
                    if self.observe_text(text, title_contains=title_contains):
                        return True
                    # 验证简化：仅基于视觉确认，避免剪贴板复制阻塞
                    try:
                        if self.observe_text(text, title_contains=title_contains):
                            return True
                    except Exception:
                        pass
            except Exception:
                pass
            # 最后一次尝试：再敲一次 Enter
            if send_keys is not None:
                try:
                    send_keys("{ENTER}")
                    time.sleep(0.8)
                    if self.observe_text(text, title_contains=title_contains):
                        return True
                    # 验证：输入框是否清空
                    try:
                        # 验证简化：仅做视觉确认，避免剪贴板复制阻塞
                        try:
                            if self.observe_text(text, title_contains=title_contains):
                                return True
                        except Exception:
                            pass
                    except Exception:
                        pass
                except Exception:
                    pass
            return False
        except Exception:
            return False

    # ---------- observe–act–verify orchestration ----------
    def observe_act_verify(self, action_name: str, act_fn, verify_fn, precheck_fn=None, timeout_sec: float = 8.0, poll_interval: float = 0.6) -> bool:
        """
        Generic driver: optional precheck -> act -> verify, retry loop.
        Mirrors OpenInterpreter’s loop to remain robust under flaky vision.
        """
        try:
            if callable(precheck_fn):
                try:
                    if precheck_fn():
                        return True
                except Exception:
                    pass
            start = time.time()
            while (time.time() - start) < timeout_sec:
                try:
                    act_fn()
                except Exception:
                    pass
                time.sleep(poll_interval)
                try:
                    if verify_fn():
                        return True
                except Exception:
                    pass
            return False
        except Exception:
            return False

    def read_edit_text(self, title_contains: Optional[str] = None) -> Optional[str]:
        try:
            from .logger import log_event
            log_event("READ_EDIT_START", f"title={title_contains}")
            
            # 先尝试 UIA，失败再回退 win32（兼容 Win10 记事本）
            from pywinauto import Desktop
            # UIA 路径
            try:
                log_event("READ_EDIT_UIA", "trying_uia_backend")
                d = Desktop(backend="uia")
                win = None
                if title_contains:
                    pattern = f".*{re.escape(title_contains)}.*"
                    # 处理多个匹配窗口的情况
                    try:
                        win = d.window(title_re=pattern)
                        log_event("READ_EDIT_UIA", f"window_pattern={pattern}")
                    except Exception as e:
                        if "3 elements that match" in str(e) or "multiple" in str(e).lower():
                            # 有多个匹配，尝试获取所有匹配的窗口并选择第一个可见的
                            try:
                                windows = d.windows(title_re=pattern)
                                for w in windows:
                                    if w.is_visible():
                                        win = w
                                        log_event("READ_EDIT_UIA", f"selected_visible_window={w.window_text()}")
                                        break
                                if not win and windows:
                                    win = windows[0]  # 如果没有可见的，选择第一个
                                    log_event("READ_EDIT_UIA", f"selected_first_window={win.window_text()}")
                            except Exception as e2:
                                log_event("READ_EDIT_UIA", f"multiple_window_handling_fail={e2}")
                                raise e
                        else:
                            raise e
                else:
                    win = d.active_window()
                    log_event("READ_EDIT_UIA", "using_active_window")
                
                if win and win.exists():
                    log_event("READ_EDIT_UIA", "window_found")
                    for ct in ["Edit", "Document", "Text"]:
                        try:
                            log_event("READ_EDIT_UIA", f"trying_control_type={ct}")
                            elem = win.child_window(control_type=ct)
                            if elem.exists():
                                log_event("READ_EDIT_UIA", f"control_found={ct}")
                                w = elem.wrapper_object()
                                val = None
                                try:
                                    val = w.get_value()
                                    log_event("READ_EDIT_UIA", f"get_value={repr(val)}")
                                except Exception as e:
                                    log_event("READ_EDIT_UIA", f"get_value_fail={e}")
                                    try:
                                        val = w.window_text()
                                        log_event("READ_EDIT_UIA", f"window_text={repr(val)}")
                                    except Exception as e2:
                                        log_event("READ_EDIT_UIA", f"window_text_fail={e2}")
                                        val = None
                                if not val:
                                    try:
                                        vals = w.texts()
                                        if vals:
                                            val = "\n".join([v for v in vals if isinstance(v, str)])
                                            log_event("READ_EDIT_UIA", f"texts={repr(val)}")
                                    except Exception as e:
                                        log_event("READ_EDIT_UIA", f"texts_fail={e}")
                                        pass
                                if isinstance(val, str) and val.strip():
                                    log_event("READ_EDIT_SUCCESS", f"uia_result={repr(val)}")
                                    return val
                            else:
                                log_event("READ_EDIT_UIA", f"control_not_found={ct}")
                        except Exception as e:
                            log_event("READ_EDIT_UIA", f"control_error={ct}, error={e}")
                            continue
                else:
                    log_event("READ_EDIT_UIA", "window_not_found_or_not_exists")
            except Exception as e:
                log_event("READ_EDIT_UIA", f"uia_exception={e}")
                pass
            # win32 路径
            try:
                log_event("READ_EDIT_WIN32", "trying_win32_backend")
                d = Desktop(backend="win32")
                win = None
                if title_contains:
                    pattern = f".*{re.escape(title_contains)}.*"
                    # 处理多个匹配窗口的情况
                    try:
                        win = d.window(title_re=pattern)
                        log_event("READ_EDIT_WIN32", f"window_pattern={pattern}")
                    except Exception as e:
                        if "3 elements that match" in str(e) or "multiple" in str(e).lower():
                            # 有多个匹配，尝试获取所有匹配的窗口并选择第一个可见的
                            try:
                                windows = d.windows(title_re=pattern)
                                for w in windows:
                                    if w.is_visible():
                                        win = w
                                        log_event("READ_EDIT_WIN32", f"selected_visible_window={w.window_text()}")
                                        break
                                if not win and windows:
                                    win = windows[0]  # 如果没有可见的，选择第一个
                                    log_event("READ_EDIT_WIN32", f"selected_first_window={win.window_text()}")
                            except Exception as e2:
                                log_event("READ_EDIT_WIN32", f"multiple_window_handling_fail={e2}")
                                raise e
                        else:
                            raise e
                else:
                    win = d.active()
                    log_event("READ_EDIT_WIN32", "using_active_window")
                
                if not win:
                    log_event("READ_EDIT_WIN32", "window_not_found")
                    return None
                
                log_event("READ_EDIT_WIN32", "window_found")
                # 记事本编辑控件通常为 class_name="Edit"
                try:
                    ed = win.child_window(class_name="Edit").wrapper_object()
                    log_event("READ_EDIT_WIN32", "edit_control_found")
                except Exception as e:
                    log_event("READ_EDIT_WIN32", f"edit_control_fail={e}")
                    ed = None
                
                if ed is None:
                    log_event("READ_EDIT_WIN32", "edit_control_none")
                    return None
                
                val = None
                try:
                    val = ed.window_text()
                    log_event("READ_EDIT_WIN32", f"window_text={repr(val)}")
                except Exception as e:
                    log_event("READ_EDIT_WIN32", f"window_text_fail={e}")
                    val = None
                
                if not (isinstance(val, str) and val.strip()):
                    try:
                        vals = ed.texts()
                        if vals:
                            val = "\n".join([v for v in vals if isinstance(v, str)])
                            log_event("READ_EDIT_WIN32", f"texts={repr(val)}")
                    except Exception as e:
                        log_event("READ_EDIT_WIN32", f"texts_fail={e}")
                        pass
                
                if isinstance(val, str):
                    log_event("READ_EDIT_SUCCESS", f"win32_result={repr(val)}")
                    return val
                else:
                    log_event("READ_EDIT_WIN32", f"final_val_invalid={repr(val)}")
            except Exception as e:
                log_event("READ_EDIT_WIN32", f"win32_exception={e}")
                pass
            return None
        except Exception:
            return None